from typing import Optional
import os
import random
import ffmpeg
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (
    QWidget, QLabel, QLineEdit, QPushButton, QComboBox, QGridLayout, QVBoxLayout,
    QColorDialog, QFontComboBox, QSpinBox, QHBoxLayout, QMessageBox, QProgressBar,
    QFileDialog, QTabWidget
)

from app.core.ffmpeg_utils import get_ffmpeg_exe, get_ffprobe_exe
from app.ui.subtitle_editor import SubtitleEditor
from app.ui.subtitle_export_dialog import SubtitleExportDialog


class SubtitlesThread(QThread):
    finished = pyqtSignal(bool, str)

    def __init__(self, video_path: str, subtitle_path: str, output_path: str,
                 font_name: str, font_size: int, color: QColor, outline: int,
                 shadow: int, alignment: int, margin_v: int):
        super().__init__()
        self.video_path = video_path
        self.subtitle_path = subtitle_path
        self.output_path = output_path
        self.font_name = font_name
        self.font_size = font_size
        self.color = color
        self.outline = outline
        self.shadow = shadow
        self.alignment = alignment
        self.margin_v = margin_v

    @staticmethod
    def _qcolor_to_ass_primary_colour(color: QColor) -> str:
        r, g, b = color.red(), color.green(), color.blue()
        return f"&H00{b:02X}{g:02X}{r:02X}&"

    def run(self) -> None:
        try:
            exe = get_ffmpeg_exe()
            if not exe:
                raise FileNotFoundError("未找到 ffmpeg，可安装 imageio-ffmpeg 或将 ffmpeg 加入 PATH")
            if not os.path.exists(self.video_path):
                raise FileNotFoundError("视频文件不存在")
            if not os.path.exists(self.subtitle_path):
                raise FileNotFoundError("字幕文件不存在")

            style = ",".join([
                f"Fontname={self.font_name}",
                f"Fontsize={self.font_size}",
                f"PrimaryColour={self._qcolor_to_ass_primary_colour(self.color)}",
                f"Outline={self.outline}",
                f"Shadow={self.shadow}",
                f"Alignment={self._align_idx_to_ass(self.alignment)}",
                f"MarginV={self.margin_v}",
                "BorderStyle=1",
            ])

            ffprobe_exe = get_ffprobe_exe() or 'ffprobe'
            probe = ffmpeg.probe(self.video_path, cmd=ffprobe_exe)
            has_audio = any(s.get('codec_type') == 'audio' for s in probe.get('streams', []))

            inp = ffmpeg.input(self.video_path)
            v = inp.video.filter('subtitles', filename=self.subtitle_path, force_style=style)

            if has_audio:
                out = ffmpeg.output(v, inp.audio, self.output_path, vcodec='libx264', acodec='copy', preset='veryfast', movflags='+faststart')
            else:
                out = ffmpeg.output(v, self.output_path, vcodec='libx264', preset='veryfast', movflags='+faststart')

            ffmpeg.run(out, overwrite_output=True, cmd=exe)
            self.finished.emit(True, self.output_path)
        except Exception as exc:
            self.finished.emit(False, str(exc))


class SubtitlesWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.subtitle_editor = None
        self._build_ui()
        self._wire()
        self.thread: Optional[SubtitlesThread] = None
        self.sim_timer = QTimer(self)
        self.sim_timer.setInterval(150)
        self.sim_timer.timeout.connect(self._on_sim)
        self.simulating = False
        self.actual_done = False
        self.current_color = QColor(255, 255, 255)
        self._apply_color_btn()

    def _build_ui(self):
        # 创建标签页控件
        self.tab_widget = QTabWidget()
        
        # 第一个标签页：字幕编辑器
        self.subtitle_editor = SubtitleEditor()
        self.tab_widget.addTab(self.subtitle_editor, "字幕编辑器")
        
        # 第二个标签页：字幕烧录
        self.burn_widget = QWidget()
        self._build_burn_ui()
        self.tab_widget.addTab(self.burn_widget, "字幕烧录")
        
        # 主布局
        lay = QVBoxLayout(self)
        lay.addWidget(self.tab_widget)
        self.setLayout(lay)
        
        # 连接字幕编辑器的导出信号
        self.subtitle_editor.export_btn.clicked.disconnect()
        self.subtitle_editor.export_btn.clicked.connect(self._show_export_dialog)

    def _build_burn_ui(self):
        """构建字幕烧录界面"""
        self.video_edit = QLineEdit(self.burn_widget)
        self.video_btn = QPushButton("浏览视频", self.burn_widget)
        self.sub_edit = QLineEdit(self.burn_widget)
        self.sub_btn = QPushButton("浏览字幕", self.burn_widget)
        self.output_edit = QLineEdit(self.burn_widget)
        self.output_btn = QPushButton("保存到", self.burn_widget)
        self.font_combo = QFontComboBox(self.burn_widget)
        self.font_size = QSpinBox(self.burn_widget)
        self.font_size.setRange(8, 96)
        self.font_size.setValue(32)
        self.color_btn = QPushButton("选择颜色", self.burn_widget)
        self.outline_spin = QSpinBox(self.burn_widget)
        self.outline_spin.setRange(0, 10)
        self.outline_spin.setValue(2)
        self.shadow_spin = QSpinBox(self.burn_widget)
        self.shadow_spin.setRange(0, 10)
        self.shadow_spin.setValue(1)
        self.alignment_combo = QComboBox(self.burn_widget)
        self.alignment_combo.addItems(["左下","中下","右下","左中","正中","右中","左上","中上","右上"])
        self.alignment_combo.setCurrentIndex(1)
        self.margin_v_spin = QSpinBox(self.burn_widget)
        self.margin_v_spin.setRange(0, 200)
        self.margin_v_spin.setValue(20)
        self.progress_bar = QProgressBar(self.burn_widget)
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(0)
        self.start_btn = QPushButton("开始生成", self.burn_widget)

        grid = QGridLayout()
        r = 0
        grid.addWidget(QLabel("视频文件:"), r, 0); grid.addWidget(self.video_edit, r, 1); grid.addWidget(self.video_btn, r, 2); r += 1
        grid.addWidget(QLabel("字幕文件(.srt/.ass):"), r, 0); grid.addWidget(self.sub_edit, r, 1); grid.addWidget(self.sub_btn, r, 2); r += 1
        grid.addWidget(QLabel("输出视频:"), r, 0); grid.addWidget(self.output_edit, r, 1); grid.addWidget(self.output_btn, r, 2); r += 1
        grid.addWidget(QLabel("字体/大小:"), r, 0)
        row2 = QHBoxLayout(); row2.addWidget(self.font_combo); row2.addWidget(self.font_size); grid.addLayout(row2, r, 1, 1, 2); r += 1
        grid.addWidget(QLabel("颜色:"), r, 0); grid.addWidget(self.color_btn, r, 1); r += 1
        grid.addWidget(QLabel("描边/阴影/对齐/下边距:"), r, 0)
        row3 = QHBoxLayout()
        for w in (QLabel("描边"), self.outline_spin, QLabel("阴影"), self.shadow_spin, QLabel("对齐"), self.alignment_combo, QLabel("MarginV"), self.margin_v_spin):
            row3.addWidget(w)
        grid.addLayout(row3, r, 1, 1, 2); r += 1

        lay = QVBoxLayout(self.burn_widget)
        lay.addLayout(grid)
        lay.addWidget(self.progress_bar)
        lay.addWidget(self.start_btn, 0, Qt.AlignRight)

    def _wire(self):
        self.video_btn.clicked.connect(self._pick_video)
        self.sub_btn.clicked.connect(self._pick_sub)
        self.output_btn.clicked.connect(self._pick_out)
        self.color_btn.clicked.connect(self._pick_color)
        self.start_btn.clicked.connect(self._start)

    def _show_export_dialog(self):
        """显示导出对话框"""
        if not self.subtitle_editor.subtitles:
            QMessageBox.warning(self, "警告", "请先添加一些字幕内容")
            return
            
        dialog = SubtitleExportDialog(self.subtitle_editor.subtitles, self)
        dialog.exec_()

    def _apply_color_btn(self):
        c = self.current_color
        self.color_btn.setStyleSheet(f"background-color: rgb({c.red()},{c.green()},{c.blue()}); color:#000;")

    def _pick_video(self):
        p, _ = QFileDialog.getOpenFileName(self, "选择视频", "", "视频文件 (*.mp4 *.mkv *.mov *.avi *.flv *.wmv *.webm)")
        if p: self.video_edit.setText(p)

    def _pick_sub(self):
        p, _ = QFileDialog.getOpenFileName(self, "选择字幕", "", "字幕文件 (*.srt *.ass)")
        if p: self.sub_edit.setText(p)

    def _pick_out(self):
        p, _ = QFileDialog.getSaveFileName(self, "保存输出", "", "视频文件 (*.mp4)")
        if p: self.output_edit.setText(p)

    def _pick_color(self):
        color = QColorDialog.getColor(self.current_color, self, "选择字幕颜色")
        if color.isValid():
            self.current_color = color
            self._apply_color_btn()

    @staticmethod
    def _align_idx_to_ass(idx: int) -> int:
        return [1,2,3,4,5,6,7,8,9][idx]

    def _start(self):
        if self.thread is not None and self.thread.isRunning():
            return
        v = self.video_edit.text().strip()
        s = self.sub_edit.text().strip()
        o = self.output_edit.text().strip()
        if not v: QMessageBox.warning(self, "提示", "请选择视频文件"); return
        if not s: QMessageBox.warning(self, "提示", "请选择字幕文件"); return
        if not o: QMessageBox.warning(self, "提示", "请选择输出位置"); return

        self.progress_bar.setValue(0)
        self.simulating = True
        self.actual_done = False
        self.sim_timer.start()
        self.start_btn.setEnabled(False)

        self.thread = SubtitlesThread(
            video_path=v,
            subtitle_path=s,
            output_path=o,
            font_name=self.font_combo.currentFont().family(),
            font_size=int(self.font_size.value()),
            color=self.current_color,
            outline=int(self.outline_spin.value()),
            shadow=int(self.shadow_spin.value()),
            alignment=self._align_idx_to_ass(self.alignment_combo.currentIndex()),
            margin_v=int(self.margin_v_spin.value()),
        )
        self.thread.finished.connect(self._done)
        self.thread.start()

    def _on_sim(self):
        if not self.simulating: return
        v = self.progress_bar.value()
        if self.actual_done:
            self.progress_bar.setValue(100)
            self.sim_timer.stop(); self.simulating = False; return
        if v < 97:
            self.progress_bar.setValue(min(97, v + random.randint(1,3)))

    def _done(self, ok: bool, msg: str):
        self.actual_done = True
        if ok:
            QMessageBox.information(self, "成功", f"生成完成！\n输出文件: {msg}")
        else:
            self.simulating = False; self.sim_timer.stop(); self.progress_bar.setValue(0)
            QMessageBox.critical(self, "错误", msg)
        self.start_btn.setEnabled(True)


